/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package serveur;


import java.io.*;
import java.net.Socket;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLSocket;

/**
 *
 * @author scriptoff
 */
class TraitementClient implements Runnable {
    
    private DataInputStream entree ;
    private DataOutputStream sortie ;
    private Utilisateur utilisateur ;
    private Chat chat ;
    private SSLSocket socket_transfert;
    private boolean connecte ;

    public TraitementClient(SSLSocket socket_transfert, Chat chat ) {
        connecte = true ;
        this.chat = chat;
        this.socket_transfert = socket_transfert;
        utilisateur = null ;
        try {
            entree = new DataInputStream(socket_transfert.getInputStream());
            sortie = new DataOutputStream(socket_transfert.getOutputStream());
        } catch (Exception ex) {
                new TraiteException(ex,"TraitementClient");     
        }
    }

    public void run() {
        try {

            while (  utilisateur == null  ){
                short commande = entree.readShort();
                if ( commande == CodeCommande.COMMANDE_CONNECTION_CHAT  )
                    traiterCommandeConnectionChat();
                else if ( commande == CodeCommande.COMMANDE_INSCRIPTION_CHAT )
                    traiterCommandeInscriptionChat();
            }
            while ( true ){
                short commande = entree.readShort();
                traiterCommandes(commande);
            }

        }catch (Exception ex) {
            if (utilisateur != null){
                new TraiteException(ex,"run");
                chat.deconnectionChat(this);
                try {
                    socket_transfert.close();
                } catch (Exception ex1) {
                    new TraiteException(ex1,"run");
                }
                connecte = false ;
            } else {
                 try {
                    socket_transfert.close();
                } catch (Exception ex1) {
                    new TraiteException(ex1,"run");
                }
            }
        }
    }

    public  Utilisateur getUtilisateur() {
        return utilisateur ;
    }

    public void  supprimerUtilisateur() {
        utilisateur = null ;
    }

    void envoyerErreurUtilisateurExpulser(String nomCanal) throws IOException {
        sortie.writeShort(CodeCommande.COMMANDE_ERREUR_UTILISATEUR_EXPULSER);
        sortie.writeUTF(nomCanal);
    }

    void envoyerCommandeDialogue(String pseudo) throws IOException {
        sortie.writeShort(CodeCommande.COMMANDE_DIALOGUER);
        sortie.writeUTF(pseudo);
    }



    /*// tu veux pas les mettre autres parts ces trucs ? car ils encombrent le code et ils nous servent pas trop
    private void traitementByte() {
    try {
    byte b = entree.readByte();
    System.out.println("Valeur:" + b);
    } catch (IOException ex) {
    System.err.println("Probleme lors d'E/S ");
    }
    }
    private void traitementTabByte() {
    try {
    String s = entree.readUTF();
    int i = entree.readInt();
    byte []  btab = new byte[i]  ;
    entree.read(btab);
    FileOutputStream fos = new FileOutputStream(s);
    fos.write(btab);
    } catch (IOException ex) {
    System.err.println("Probleme lors d'E/S ");
    } catch (NegativeArraySizeException ex) {
    System.err.println("Probleme lors de l'envoi de la taille du tableau d'octet ( négatif )");
    }

    }
    private void traitementReel() {
    try {
    float f = entree.readFloat();
    System.out.println("Valeur:" + f);
    } catch (IOException ex) {
    System.err.println("Probleme lors d'E/S ");
    }
    }

    private void traitementUTF() {
    try {
    String s = entree.readUTF();
    System.out.println("Valeur:" + s);
    } catch (IOException ex) {
    System.err.println("Probleme lors d'E/S ");
    }
    }*/

    private void traiterCommandes(short commande) throws NullPointerException, IOException {
        boolean sauvegarder = true ;
        switch ( commande ){
            case CodeCommande.COMMANDE_BANNIR_UTILISATEUR_CANAL :
                traiterCommandeBannirUtilisateurCanal();
                break;
            case CodeCommande.COMMANDE_DEBANNIR_UTILISATEUR_CANAL:
                traiteCommandeDeBannirUtilisateurCanal();
                break;
            case CodeCommande.COMMANDE_CREER_REJOINDRE_CANAL :
                traiterCommandeCreerRejoindreCanal();
                break;
            case CodeCommande.COMMANDE_ENVOYER_LISTE_CANAUX :
                traiterCommandeEnvoyerListeCanaux() ;
                sauvegarder = false ;
                break;
            case CodeCommande.COMMANDE_ENVOYER_MESSAGE :
                traiterCommandeEnvoyerMessage();
                sauvegarder = false ;
                break;
            case CodeCommande.COMMANDE_SUPPRIMER_SUPERUTILISATEUR :
                traiterCommandeSupprimerSuperUtilisateur();
                break ;
            case CodeCommande.COMMANDE_NOUVEAU_SUPERUTILISATEUR :
                traiterCommandeNouveauSuperUtilisateur();
                break;
            case CodeCommande.COMMANDE_DECONNECTION_CHAT :
                traiterCommandeDeconnectionChat();
                break;
            case CodeCommande.COMMANDE_QUITTER_CANAL :
                traiterCommandeQuitterCanal();
                break;
            case CodeCommande.COMMANDE_MODIFIER_PARAMETRES_PERSONNELS :
                traiterCommandeModifierParametresPersonnels();
                break;
            case CodeCommande.COMMANDE_MODIFIER_PASSWORD_CANAL :
                traiterCommandeModifierPasswordCanal();
                break;
            case CodeCommande.COMMANDE_EXPULSER_UTILISATEUR_CANAL :
                traiterCommandeExpulserUtilisateurCanal();
                break;
            case CodeCommande.COMMANDE_SUPPRIMER_CANAL :
                traiterCommandeSupprimerCanal();
                break;
            case CodeCommande.COMMANDE_DIALOGUER :
                traiterCommandeDialoguer();
            default :
                sauvegarder = false ;
                break;
        }
        if (sauvegarder)sauvegarderChat();
    }

    private void traiterCommandeConnectionChat() throws NullPointerException, IOException {
        String pseudo = entree.readUTF();
        String password = entree.readUTF();
        chat.connectionChat(this, pseudo, password);
        sauvegarderChat();
    }

    private void traiterCommandeInscriptionChat() throws NullPointerException, IOException {
        String pseudo = entree.readUTF();
        String password = entree.readUTF();
        chat.inscriptionChat( this , pseudo, password);
        sauvegarderChat();
    }

    private void  traiterCommandeBannirUtilisateurCanal() throws NullPointerException, IOException {
        String nomCanal = entree.readUTF();
        String pseudoABannir = entree.readUTF();
        if (pseudoABannir.charAt(0) == '@')
            pseudoABannir = pseudoABannir.substring(1, pseudoABannir.length());
        chat.bannirUtilisateur(this, nomCanal, pseudoABannir);
    }

    private void traiteCommandeDeBannirUtilisateurCanal() throws NullPointerException, IOException {
        String nomCanal = entree.readUTF();
        String pseudoADeBannir = entree.readUTF();
        if (pseudoADeBannir.charAt(0) == '@')
            pseudoADeBannir = pseudoADeBannir.substring(1, pseudoADeBannir.length());
        chat.deBannirUtilisateur(this, nomCanal, pseudoADeBannir);
    }

    private void traiterCommandeCreerRejoindreCanal() throws NullPointerException, IOException {
        String nomCanal = entree.readUTF();
        String password = entree.readUTF();
        chat.rejoindreCreerCanal(this, nomCanal, password);
    }

    private void traiterCommandeEnvoyerListeCanaux() throws NullPointerException, IOException {
        chat.listeCanauxChat(this);
    }

    private void traiterCommandeEnvoyerMessage() throws NullPointerException, IOException {
        String argument = entree.readUTF();
        if (argument.charAt(0) == '@')
            argument = argument.substring(1, argument.length());
        String message = entree.readUTF();
        chat.envoyerMessage(this, argument, message);
    }

    private void traiterCommandeSupprimerSuperUtilisateur() throws NullPointerException, IOException {
       String nomCanal = entree.readUTF();
       String pseudoSuperUtilisateur = entree.readUTF();
       if (pseudoSuperUtilisateur.charAt(0) == '@')
            pseudoSuperUtilisateur = pseudoSuperUtilisateur.substring(1, pseudoSuperUtilisateur.length());
       chat.supprimerSuperUtilisateur(this, nomCanal, pseudoSuperUtilisateur);
    }

    private void traiterCommandeNouveauSuperUtilisateur() throws NullPointerException, IOException {
        String nomCanal = entree.readUTF();
        String pseudoDuNouveauSuperUtilisateur = entree.readUTF();
        if (pseudoDuNouveauSuperUtilisateur.charAt(0) == '@')
            pseudoDuNouveauSuperUtilisateur  = pseudoDuNouveauSuperUtilisateur.substring(1, pseudoDuNouveauSuperUtilisateur.length());
        chat.nouveauSuperUtilisateur(this, nomCanal, pseudoDuNouveauSuperUtilisateur);
    }

    private void traiterCommandeDeconnectionChat() throws NullPointerException, IOException {
        chat.deconnectionChat(this);
        connecte = false ;
        socket_transfert.close();
    }

    private void traiterCommandeDialoguer() throws NullPointerException, IOException {
        String pseudo = entree.readUTF();
        if (pseudo.charAt(0) == '@')
            pseudo  = pseudo.substring(1, pseudo.length());
        chat.dialoguer( this , pseudo);
    }

    private void traiterCommandeQuitterCanal() throws NullPointerException, IOException {
        String nomCanal = entree.readUTF();
        chat.quitterCanal(this, nomCanal);
    }

    private void traiterCommandeModifierParametresPersonnels() throws NullPointerException, IOException {
        String ancienPassword = entree.readUTF();
        String nouveauPassword = entree.readUTF();
        chat.modifierParametresUtilisateur(this, ancienPassword, nouveauPassword);
    }

    private void traiterCommandeModifierPasswordCanal() throws NullPointerException, IOException {
        String nomCanal = entree.readUTF();
        String password = entree.readUTF();
        chat.modifierPasswordCanal(this, nomCanal, password);
    }

    private void traiterCommandeExpulserUtilisateurCanal() throws NullPointerException, IOException {
        String nomCanal = entree.readUTF();
        String pseudoAExpulser = entree.readUTF();
        if (pseudoAExpulser.charAt(0) == '@')
            pseudoAExpulser = pseudoAExpulser.substring(1, pseudoAExpulser.length());
        chat.expulserUtilisateur(this, nomCanal, pseudoAExpulser);
    }

    private void traiterCommandeSupprimerCanal() throws NullPointerException, IOException {
        String nomCanal = entree.readUTF();
        chat.supprimerCanal(this, nomCanal);
    }
    
        public void raffraichirCanal ( String nomCanal , CopyOnWriteArraySet<String> listeUtilisateurs ) throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_RAFFRAICHIR_CANAL);
        sortie.writeUTF(nomCanal);
        sortie.writeInt(listeUtilisateurs.size());
        for ( String str : listeUtilisateurs ){
            sortie.writeUTF(str);
        }
    }
        
        
    public void envoyerErreurPassword () throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_ERREUR_PASSWORD);
    }
    public void envoyerListeCanaux ( ConcurrentHashMap<String,Canal> canaux ) throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_ENVOYER_LISTE_CANAUX);
        Set<String> nomCanaux =   canaux.keySet() ;
        sortie.writeInt(nomCanaux.size());
        for ( String str : nomCanaux  ){
            sortie.writeUTF(str);
        }

    }
    public void envoyerErreurInscription (  ) throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_ERREUR_INSCRIPTION);
    }
    public void ajouterUtilisateur( Utilisateur utilisateur )
    {
        this.utilisateur = utilisateur;
    }
    public void envoyerInscriptionOk() throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_INSCRIPTION_OK);
    }
    public void envoyerErreurConnection() throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_ERREUR_CONNECTION);
    }

    public void envoyerErreurDroitsInsuffisants (  ) throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_ERREUR_DROITS_INSUFFISANTS_CANAL);
    }
    public void envoyerConnectionOk() throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_CONNECTION_OK);
    }
    public void envoyerBannirUtilsateurOk (  ) throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_BANNIR_UTILISATEUR_OK);
    }
    public void envoyerModifierPasswordCanalOk (  ) throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_MODIFIER_PASSWORD_CANAL_OK);
    }
    public void envoyerDeBannirUtilisateurOk (  ) throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_DEBANNIR_UTILISATEUR_OK);
    }
    public void envoyerMessageCanal ( String nomUtilisateur , String canal , String message ) throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_RAFFRAICHIR_MESSAGE_CANAL);
        sortie.writeUTF(nomUtilisateur);
        sortie.writeUTF(canal);
        sortie.writeUTF(message);
    }
    public void envoyerMessageUtilisateur ( String pseudoEnvoyeur , String pseudoReceveur  , String message ) throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_RAFFRAICHIR_MESSAGE_UTILISATEUR);
        sortie.writeUTF(pseudoEnvoyeur);
        sortie.writeUTF(pseudoReceveur);
        sortie.writeUTF(message);
    }
    public void envoyerCanalSupprime( String nomcanal ) throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_CANAL_SUPPRIME);
        sortie.writeUTF(nomcanal);
    }

    void envoyerErreurUtilisateurBanni() throws IOException
    {
        sortie.writeShort(CodeCommande.COMMANDE_ERREUR_UTILISATEUR_BANNI);
    }

    void envoyerModifierParametresPersonnelsOk() throws IOException {
        sortie.writeShort(CodeCommande.COMMANDE_MODIFIER_PARAMETRES_PERSONNELS_OK);
    }
    private String enleverArobase(String str){
        String retour = str ;
        if (str.charAt(0) == '@')
            retour = str.substring(1, str.length());
        return retour ;
    }
    private void sauvegarderChat(){
        String nomfich = "bd.data";
        try  {
                FileOutputStream f = new FileOutputStream(nomfich);
                ObjectOutputStream out = new ObjectOutputStream(f);

                out.writeObject(chat);

            }
            catch (Exception e)  {

            }

    }
}
